package com.zt.bus.order.service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import com.zt.bus.util.DatetimeUtil;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.zt.bus.assistant.model.LineStop;
import com.zt.bus.constant.BusConstant;
import com.zt.bus.line.model.Line;
import com.zt.bus.line.model.LinePlan;
import com.zt.bus.line.service.LinePlanService;
import com.zt.bus.line.service.LineService;
import com.zt.bus.order.inter.OrderDetailMapper;
import com.zt.bus.order.inter.OrderMapper;
import com.zt.bus.order.model.Order;
import com.zt.bus.order.model.OrderDetail;
import com.zt.bus.order.model.OrderDetailPassenger;
import com.zt.bus.order.model.OrderDiscount;
import com.zt.bus.order.model.Passenger;
import com.zt.bus.util.DesUtils;
import com.zt.servlet.FieldAlias;
import com.zt.servlet.ReqBean;
import com.zt.servlet.Response;
import com.zt.shiro.GlobalInput;
import com.zt.system.model.BusinessException;
import com.zt.system.model.SqlBuilder;
import com.zt.system.service.BaseService;
import com.zt.util.DateUtil;
import com.zt.util.StringUtil;

@Service
public class OrderService extends BaseService {

    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private OrderDetailMapper orderDetailMapper;
    @Autowired
    private LineService lineService;
    @Autowired
    private LinePlanService linePlanService;
    @Autowired
    private OrderAmountService orderAmountService;
    @Autowired
    private OrderStatusCheckService orderStatusCheckService;

    /**
     * 查询
     * 
     * @param reqBean
     * @return
     */
    public JSONObject getTable(ReqBean reqBean) {
        SqlBuilder sqlBuilder = new SqlBuilder("select * from DZ_ORDER where 1 = 1 ");
        sqlBuilder.addWhereLike2("BOOK_USER_PHONE", reqBean.getInfo("bookUserPhone"));
        sqlBuilder.addWhere("C_ORDER_STATUS", reqBean.getInfo("orderStatus"));
        sqlBuilder.addWhere("PLAN_ID", reqBean.getInfo("planId"));
        sqlBuilder.orderBy(" ORDER BY MAKE_TIME desc");
        return queryTable(sqlBuilder, reqBean.getPageSize(), reqBean.getPageIndex());
    }

    /**
     * 待支付列表
     * 
     * @param bookUserPhone
     * @return
     */
    @FieldAlias(service = "codeService", field = "orderStatus", alias = "orderStatusName", param = "orderstatus")
    public JSONArray getToBePaid(String bookUserPhone) {
        if (StringUtil.isEmpty(bookUserPhone)) {
            throw new BusinessException("获取用户信息失败!");
        }
        ReqBean reqBean = new ReqBean();
        reqBean.addInfo("bookUserPhone", bookUserPhone);
        JSONArray array = new JSONArray(), rows = getTable(reqBean).getJSONArray("rows");
        for (int i = 0; i < rows.size(); i++) {
            JSONObject json = rows.getJSONObject(i);
            String status = json.getString("orderStatus");
            if (BusConstant.PaymentStatus.TO_BE_CONFIRMED.equals(status)
                    || BusConstant.PaymentStatus.TO_BE_PAID.equals(status)
                    || BusConstant.PaymentStatus.PAYMENT_FAILED.equals(status)
                    || BusConstant.PaymentStatus.PAYMENT_CANCEL.equals(status)) {
                array.add(json);
            }
        }
        return array;
    }

    /**
     * 已支付列表
     * 
     * @param bookUserPhone
     * @return
     */
    @FieldAlias(service = "codeService", field = "orderStatus", alias = "orderStatusName", param = "orderstatus")
    public JSONArray getHasPaid(String bookUserPhone) {
        if (StringUtil.isEmpty(bookUserPhone)) {
            throw new BusinessException("获取用户信息失败!");
        }
        ReqBean reqBean = new ReqBean();
        reqBean.addInfo("bookUserPhone", bookUserPhone);
        JSONArray array = new JSONArray(), rows = getTable(reqBean).getJSONArray("rows");
        for (int i = 0; i < rows.size(); i++) {
            JSONObject json = rows.getJSONObject(i);
            String status = json.getString("orderStatus");
            if (BusConstant.PaymentStatus.PAYMENT_SUCCESSFUL.equals(status)) {
                array.add(json);
            }
        }
        return array;
    }

    /**
     * 获取订单乘客预订详情
     * 
     * @param orderId
     * @return
     */
    public List<OrderDetailPassenger> getOrderDetailPassenger(String orderId) {
        if (StringUtil.isEmpty(orderId)) {
            throw new BusinessException("获取订单号失败!");
        }
        return getOrderDetailPassenger(orderDetailMapper.selectByOrderId(orderId));
    }

    /**
     * 未发车的乘客及订单
     * 
     * @param planId
     * @return
     */
    public List<OrderDetailPassenger> getNotDepartOrders(String planId) {
        LinePlan plan = linePlanService.getById(planId);
        Date startDate = new Date();
        if (BusConstant.LinePlanStatus.TO_BE_OPEN.equals(plan.getPlanStatus())) {// 待开
            startDate = DateUtil.parse("2017-06-26");// 这一天写的这块的代码
        } else if (isDepart(new Date(), new Date(), plan.getDepartTime())) {// 今天已经发车了
            startDate = DateUtil.addDay(startDate, 1);
        }
        List<OrderDetail> list = new ArrayList<>();
        List<OrderDetail> orderDetailList = orderDetailMapper.selectByPlanIdAndStartDate(planId, startDate);
        for (OrderDetail orderDetail : orderDetailList) {
            if (BusConstant.OrderDetailStatus.REFUND_SUCCESS.equals(orderDetail.getStatus())) {// 去掉已退款的
                continue;
            }
            if (BusConstant.OrderDetailStatus.REFUNDING.equals(orderDetail.getStatus())) {
                throw new BusinessException("方案存在退款处理中的订单，请稍后再操作！");
            }
            list.add(orderDetail);
        }
        return getOrderDetailPassenger(list);
    }

    private List<OrderDetailPassenger> getOrderDetailPassenger(List<OrderDetail> details) {
        List<OrderDetailPassenger> list = new ArrayList<>();
        OrderDetailPassenger passenger = null;
        for (OrderDetail detail : details) {
            // 如果订单id不一致，另作为一个乘客处理
            if (passenger == null
                    || !(detail.getOrderId().equals(passenger.getOrderId()) && detail.getPassengerPhone().equals(
                            passenger.getPassengerPhone()))) {
                passenger = new OrderDetailPassenger();
                passenger.setOrderId(detail.getOrderId());
                passenger.setPassengerPhone(detail.getPassengerPhone());
                passenger.setPassengerName(detail.getPassengerName());
                LineStop stop = lineService.getStop(detail.getOnStopId());
                passenger.setOnStop(stop != null ? stop.getStopName() : "");
                list.add(passenger);
            }
            passenger.addDate(detail.getId(), detail.getRideDate(), detail.getStatus());
        }
        return list;
    }

    /**
     * 获取订单详情
     * 
     * @param orderId
     * @return
     */
    public JSONObject getDetails(String orderId) {
        if (StringUtil.isEmpty(orderId)) {
            throw new BusinessException("获取订单号失败!");
        }
        Order order = getById(orderId);
        if (order == null) {
            throw new BusinessException("订单不存在!");
        }
        JSONObject jsonRet = Order.toJson(order);
        List<OrderDetailPassenger> list = getOrderDetailPassenger(orderId);
        Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd").create();
        jsonRet.put("passengers", gson.toJson(list));

        String lineId = order.getLineId();
        if (StringUtil.isNotEmpty(lineId)) {
            Line line = lineService.getById(lineId);
            jsonRet.put("lineType", line == null ? "" : line.getLineType());
        }
        String status = order.getStatus();

        jsonRet.put("orderStatusName", BusConstant.OrderStatus.CLOSED.equals(status) ? "已关闭"
                : (BusConstant.OrderStatus.TIMEOUT_OFF.equals(status) ? "超时关闭"
                        : (BusConstant.OrderStatus.PAYMENT_CANCEL.equals(status) ? "支付取消"
                                : (BusConstant.OrderStatus.PAYMENT_FAILED.equals(status) ? "支付失败"
                                        : (BusConstant.OrderStatus.PAYMENT_SUCCESSFUL.equals(status) ? "支付成功"
                                                : (BusConstant.OrderStatus.TO_BE_CONFIRMED.equals(status) ? "支付待确认"
                                                        : (BusConstant.OrderStatus.TO_BE_PAID.equals(status) ? "待支付"
                                                                : "")))))));

        return jsonRet;
    }

    /**
     * 获取可退订订单详情
     * 
     * @param orderId
     * @return
     */
    public JSONObject getCanBackDetails(String orderId) {
        if (StringUtil.isEmpty(orderId)) {
            throw new BusinessException("获取订单号失败!");
        }
        Order order = getById(orderId);
        if (order == null) {
            throw new BusinessException("订单不存在!");
        }

        List<OrderDetailPassenger> list = getOrderDetailPassenger(orderId);
        Integer canRefundFlag = 0; // 判断该订单是否还能
        Date now = new Date();
        for (OrderDetailPassenger passenger : list) {
            for (int j = passenger.getDates().size() - 1; j >= 0; j--) {
                OrderDetailPassenger.OrderDate date = passenger.getDates().get(j);
                if (!BusConstant.OrderDetailStatus.PAYMENT_SUCCESSFUL.equals(date.getStatus())
                        || isDepart(now, date.getDate(), order.getDepartTime())) {
                    passenger.getDates().remove(date);
                }
            }
            canRefundFlag += passenger.getDates().size();
        }
        JSONObject jsonRet = Order.toJson(order);
        Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd").create();
        jsonRet.put("passengers", gson.toJson(list));
        jsonRet.put("canRefundFlag", canRefundFlag);
        LinePlan plan = linePlanService.getById(order.getPlanId());
        if (plan != null) {
            jsonRet.put("plan", plan.toJSONObject());
        }

        String lineId = order.getLineId();
        if (StringUtil.isNotEmpty(lineId)) {
            Line line = lineService.getById(lineId);
            jsonRet.put("lineType", line == null ? "" : line.getLineType());
        }

        String status = order.getStatus();
        jsonRet.put("orderStatusName", BusConstant.OrderStatus.CLOSED.equals(status) ? "已关闭"
                : (BusConstant.OrderStatus.TIMEOUT_OFF.equals(status) ? "超时关闭"
                        : (BusConstant.OrderStatus.PAYMENT_CANCEL.equals(status) ? "支付取消"
                                : (BusConstant.OrderStatus.PAYMENT_FAILED.equals(status) ? "支付失败"
                                        : (BusConstant.OrderStatus.PAYMENT_SUCCESSFUL.equals(status) ? "支付成功"
                                                : (BusConstant.OrderStatus.TO_BE_CONFIRMED.equals(status) ? "支付待确认"
                                                        : (BusConstant.OrderStatus.TO_BE_PAID.equals(status) ? "待支付"
                                                                : "")))))));

        return jsonRet;
    }

    /**
     * 判断某个订单是否发车
     * 
     * @param beCompareDateTime
     *            待判断日期
     * @param orderDate
     *            订单日期
     * @param departTime
     *            发车时间
     * 
     * @return true 已发车
     */
    public static boolean isDepart(Date beCompareDateTime, Date orderDate, String departTime) {
        return DateUtil.compare(DateUtil.formatDate(orderDate) + " " + departTime + ":00",
                DateUtil.formatDateTime(beCompareDateTime), DateUtil.FORMAT_DATE_TIME) <= 0;
    }

    /**
     * 通过id查询
     * 
     * @param orderId
     * @return
     */
    @Cacheable(value = BusConstant.Cache.ORDER, key = "#orderId")
    public Order getById(String orderId) {
        return orderMapper.selectByPrimaryKey(orderId);
    }

    /**
     * 通过planId查询支付成功的订单
     * 
     * @param planId
     * @return
     */
    public List<Order> getByPlanId(String planId) {
        return orderMapper.selectByPlanId(planId);
    }

    /**
     * 是否存在有效的订单
     * 
     * @param planId
     * @return
     */
    public boolean isHasEnableOrder(String planId) {
        return executeInt(
                "select count(0) from DZ_ORDER where PLAN_ID = ? and C_ORDER_STATUS != ? and C_ORDER_STATUS != ?",
                planId, BusConstant.OrderStatus.CLOSED, BusConstant.OrderStatus.TIMEOUT_OFF) > 0;
    }

    /**
     * 修改订单支付状态
     * 
     * @param order
     */
    @CachePut(value = BusConstant.Cache.ORDER, key = "#order.id")
    public Order updatePayStatus(Order order) {
        if (order == null || StringUtil.isEmpty(order.getId())) {
            throw new BusinessException("订单保存，缺少参数！");
        }

        //仅用于待支付、点击确认、点击取消按钮、支付失败来修改状态
        if(BusConstant.PaymentStatus.TO_BE_PAID.equals(order.getStatus())
                || BusConstant.OrderStatus.PAYMENT_CANCEL.equals(order.getStatus())
                || BusConstant.OrderStatus.TO_BE_CONFIRMED.equals(order.getStatus())
                || BusConstant.OrderStatus.PAYMENT_FAILED.equals(order.getStatus())) {
            // 修改订单表状态
            orderMapper.updateByPrimaryKeySelective(order);
            // 修改订单明细表状态
            List<OrderDetail> details = orderDetailMapper.selectByOrderId(order.getId());
            for (OrderDetail detail : details) {
                if (!order.getStatus().equals(detail.getStatus())) {
                    detail.setStatus(order.getStatus());
                    orderDetailMapper.updateByPrimaryKey(detail);
                }
            }
        }

        return order;
    }

    /**
     * 新增订单
     * 
     * @param lineId
     * @param planId
     * @param discountId
     * @param passengers
     * @param dates
     */
    public String create(String lineId, String planId, String discountId, List<Passenger> passengers, List<Date> dates) {
        if (StringUtil.isEmpty(lineId) || StringUtil.isEmpty(planId) || passengers == null || passengers.size() == 0
                || dates == null || dates.size() == 0) {
            throw new BusinessException("创建订单，缺少参数！");
        }
        Line line = lineService.getById(lineId);
        if (line == null) {
            throw new BusinessException("线路不存在！");
        }
        if (BusConstant.LineType.EMPLOYEE_BUS.equals(line.getLineType())) {// 职工专线
            // todo 判断职工是否存在
        }
        LinePlan linePlan = linePlanService.getById(planId);
        if (linePlan == null || BusConstant.LinePlanStatus.OUTAGE.equals(linePlan.getPlanStatus())
                || BusConstant.LinePlanStatus.DELETE.equals(linePlan.getPlanStatus())) {
            throw new BusinessException("方案不存在！");
        }

        // 判断剩余座位数
        JSONArray array = linePlanService.getBookableSeatingNumOfPlan(planId, dates);
        for (Object r : array) {
            JSONObject o = (JSONObject) r;
            int seating = o.optInt("seating");
            String date = o.optString("date");
            if (seating - passengers.size() < 0) {
                throw new BusinessException("线路可订座位数量不足【日期：" + date + "，剩余：" + seating + "】！");
            }
        }

        // todo 校验剩余座位上
        Order order = new Order();
        order.setId(stringId());
        order.setLineId(lineId);
        order.setLineName(line.getLineName());
        order.setPrice(line.getPrice());
        order.setPlanId(planId);
        order.setDepartTime(linePlan.getDepartTime());
        order.setBookUserId("");
        order.setBookUserName("");
        order.setBookUserPhone(GlobalInput.getCurrentUserId());
        order.setStartRideDate(dates.get(0));
        order.setPassengersNum(passengers.size());
        order.setDays(dates.size() * passengers.size()); // 订单天数 = 人数 * 订单日期
        order.setAmount(orderAmountService.getOrderAmount(lineId, planId, dates, order.getPassengersNum()));// 订单原始金额
        order.setDiscountedRate(1.0);
        order.setDiscountedAmount(order.getAmount());

        if (StringUtil.isNotEmpty(discountId)) {// 选择了折扣
            List<OrderDiscount> discounts = orderAmountService.getDiscount(lineId, planId, dates, passengers.size());
            OrderDiscount matchDiscount = null;
            for (OrderDiscount discount : discounts) {
                if (discountId.equals(discount.getDiscountId())) {
                    matchDiscount = discount;
                    break;
                }
            }
            if (matchDiscount == null) {
                throw new BusinessException("折扣信息异常！");
            }
            order.setDiscountId(discountId);
            order.setDiscountDetailId(matchDiscount.getDiscountDetailId());
            order.setDiscountName(matchDiscount.getDiscountName());
            order.setDiscountedRate(matchDiscount.getDiscountRate());
            order.setDiscountedAmount(OrderAmountService.doubleAround2(matchDiscount.getDiscountAmount()));// 折扣后金额
        }
        order.setDeductibleAmount(0.0);// 优惠券抵用
        order.setCashAmount(order.getDiscountedAmount() - order.getDeductibleAmount());
        order.setCashValue(order.getCashAmount());
        order.setStatus(BusConstant.OrderStatus.TO_BE_PAID);
        order.setMakeTime(new Date());
        order.setModifyTime(order.getMakeTime());
        order.setRemark(DatetimeUtil.formatDate(new Date(), DatetimeUtil.TIME_STAMP_PATTERN) + "00000001");
        orderMapper.insert(order);

        // 保存详情表
        List<OrderDetail> orderDetails = new ArrayList<OrderDetail>();
        for (Passenger passenger : passengers) {
            for (Date date : dates) {
                OrderDetail detail = new OrderDetail();
                detail.setId(stringId());
                detail.setOrderId(order.getId());
                detail.setPassengerName(passenger.getName());
                detail.setPassengerPhone(passenger.getPhone());
                detail.setRideDate(date);
                detail.setOnStopId(passenger.getOnStopId());
                detail.setOffStopId(passenger.getOffStopId());
                detail.setStatus(BusConstant.OrderDetailStatus.TO_BE_PAID);
                orderDetails.add(detail);
            }
        }
        orderDetailMapper.insertBatch(orderDetails);

        orderStatusCheckService.addToCheck(order);// 添加状态检查
        return order.getId();
    }

    /**
     * 方案改为已开
     * 
     * @param planId
     * @param startDate
     */
    public void planToBeOpen(String planId, Date startDate) {
        List<OrderDetailPassenger> list = getNotDepartOrders(planId);
        if (list.size() > 0) {
            List<Date> dates = linePlanService.getCanBookDays(planId, startDate);// 这里是在linePlan保存到数据库之前执行该方法，所有能够调用
            for (OrderDetailPassenger passenger : list) {
                for (int i = 0; i < passenger.getDates().size(); i++) {
                    OrderDetailPassenger.OrderDate date = passenger.getDates().get(i);
                    OrderDetail detail = new OrderDetail();
                    detail.setId(date.getId());
                    detail.setRideDate(dates.get(i));
                    orderDetailMapper.updateByPrimaryKeySelective(detail);
                }
            }
        }
    }

    /**
     * 用户取消订单 用户没有支付：直接关闭订单
     * 
     * @param orderId
     */
    public void cancel(String orderId) {
        if (StringUtil.isEmpty(orderId)) {
            throw new BusinessException("缺少参数");
        }
        Order order = orderMapper.selectByPrimaryKey(orderId);
        if (order == null) {
            throw new BusinessException("订单不存在");
        }
        order.setStatus(BusConstant.OrderStatus.CLOSED);
        orderMapper.updateByPrimaryKeySelective(order);

        orderStatusCheckService.cancelOrder(order);// 更改状态检查
    }

    /**
     * 得到当前乘客的乘车二维码加密字符串
     * 
     * @param orderId
     * @param passengerName
     * @param passengerPhone
     * @return
     */
    public JSONObject busCode(String orderId, String passengerName, String passengerPhone) {
        if (StringUtil.isEmpty(orderId) || StringUtil.isEmpty(passengerName) || StringUtil.isEmpty(passengerPhone)) {
            return Response.responseError("缺少请求参数!");
        }
        Date nowDate = new Date();

        // 验证当天是否有订单明细
        if (!isRideDate(orderId, DateUtil.formatDate(nowDate), passengerPhone)) {
            return Response.responseError("今天无乘车码!");
        }

        //手机端判断是否已申请退款或者其他非已支付状态
        String sql = "SELECT COUNT(1) FROM DZ_ORDER_DETAIL d where d.ORDER_ID = ? "
                + "AND d.PASSENGER_NAME = ? AND d.PASSENGER_PHONE = ? AND d.RIDE_DATE = ? "
                + "AND d.C_ORDER_DETAIL_STATUS = ?";
        int count = executeInt(sql, orderId, passengerName, passengerPhone, DateUtil.formatDate(nowDate),
                BusConstant.OrderStatus.PAYMENT_SUCCESSFUL);
        if(count == 0) {
            return Response.responseError(passengerName + ":" + DateUtil.formatDate(nowDate) + " 已申请退款!");
        }

        // 当前时间戳
        String encryptDate = String.valueOf(nowDate.getTime());

        String orderStr = null;
        String tempStr = "{ 'orderId' : '" + orderId + "', 'passengerName' : '" + passengerName
                + "', 'passengerPhone' : '" + passengerPhone + "', 'encryptDate' : '" + encryptDate + "'}";
        JSONObject returnJson = new JSONObject();
        try {
            DesUtils desUtils = new DesUtils();
            orderStr = desUtils.encrypt(tempStr);
        } catch (Exception e) {
            e.printStackTrace();
            return Response.responseError("加密异常");
        }
        returnJson.put("orderStr", orderStr);
        return Response.responseSuccess(returnJson);
    }

    /**
     * 当前时间是否存在订单明细
     * 
     * @param orderId
     * @param rideDate
     * @return
     */
    public boolean isRideDate(String orderId, String rideDate, String passengerPhone) {
        String sql = "select count(1) FROM DZ_ORDER_DETAIL a where a.ORDER_ID = ? AND "
                + "a.C_ORDER_DETAIL_STATUS = ? AND a.PASSENGER_PHONE = ? and a.RIDE_DATE = ?";
        int count = executeInt(sql, orderId, BusConstant.PaymentStatus.PAYMENT_SUCCESSFUL, passengerPhone, rideDate);
        return count > 0 ? true : false;
    }
}
